package com.lvmama.pangolin.task;

import com.lvmama.pangolin.core.BaseCommodityService;
import com.lvmama.pangolin.entity.CommodityRel;
import com.lvmama.pangolin.entity.RelevanceProduct;
import com.lvmama.pangolin.entity.core.BaseCommodity;
import com.lvmama.pangolin.entity.core.BaseProduct;
import com.lvmama.pangolin.enums.BusinessCode;
import com.lvmama.pangolin.enums.Company;
import com.lvmama.pangolin.reflect.ReflectTools;
import com.lvmama.pangolin.service.RelevanceCommodityService;
import com.lvmama.pangolin.service.RelevanceProductService;
import com.lvmama.pangolin.timer.CommonJob;
import com.lvmama.pangolin.util.SpringContextUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.quartz.JobExecutionContext;
import org.springframework.beans.BeanUtils;

import java.util.*;

/**
 * <h1>通用商品匹配类</h1>
 * <p>商品的实体类必须继承Commodity类</p>
 */
public class AutoMatchCommodities extends CommonJob{
    private static final Logger logger = Logger.getLogger(AutoMatchCommodities.class);
    private RelevanceProductService relevanceProductService;
    private RelevanceCommodityService relevanceCommodityService;
    private BaseCommodityService baseCommodityService;
    private RelevanceCommodityService commodityService;
    private static final String COMPANY_MT = "mt";//美团公司代码
    private static final String COMPANY_XC = "xc";//携程公司代码
    private static final String COMPANY_TN = "tn";//途牛公司代码
    private static final String COMPANY_TC = "tc";//同城公司代码
    private static final String COMPANY_QNR = "qnr";//去哪儿公司代码
    private static final String COMPANY_EL = "el";//艺龙公司代码
    private static final String COMPANY_LMM = "lmm";//驴妈妈公司代码
    private static final String COMPANY_CODE_SUFFIX = "_C_CODE";//数据库存储的公司编号后缀
    private static final String BUSINESSCODE_HOTEL="HOTEL";//业务代码：酒店：HOTEL
    private static final String BUSINESSCODE_TICKET="TICKET";//业务代码：门票：TICKET
    private static final String UNDERLINE="_";//下划线
    private static final String NONE="";//业务代码：酒店：HOTEL
    private static final String BEREPLACED_ID="prodId";//被替换的符号
    private static Map<String,Integer> counts = new HashMap<>();
    /**
     * 需要被匹配的驴妈妈商品数
     */
    private static int NEEDMATCH=0;
    /**
     * 组合商品数
     */
    private static int COMBINEDCOMMODITIES=0;


    /**
     * 进行匹配
     */
    private void matchCommodities()
    {
        try {
            beforeMatch();
            logger.info(" *** 通用商品自动匹配开始 *** ");
            /**
             * 查询产品关联关系表中所有的关联关系
             */
            List<RelevanceProduct> relevanceProducts = relevanceProductService.viewAllRelevance();
            if(relevanceProducts==null || relevanceProducts.isEmpty())
            {
                return;
            }

            logger.info(" *** 检测到数据库共有 "+relevanceProducts.size()+ " 条 产品关联信息 *** ");

            for(RelevanceProduct relevance : relevanceProducts)
            {
                BaseProduct baseProduct = new BaseProduct();
                BeanUtils.copyProperties(relevance,baseProduct);
                //返回需要进行业务匹配的公司
                List<String> companyList = needMatchCompany(baseProduct);
                /**
                 * 当需要进行匹配的公司列表不存在，或者不存在lmm的公司，则不进行本次匹配
                 */
                if((companyList==null||companyList.isEmpty())
                        ||(baseProduct==null)
                        ||(baseProduct.getProdId()==null||NONE.equals(baseProduct.getProdId())))
                {
                    continue;
                }
                /**
                 * 不需要被匹配的业务类型
                 */
                if(BUSINESSCODE_TICKET.equals(baseProduct.getBusinessCode()))
                {
                    continue;
                }
                /**
                 * 查询驴妈妈当前BUSINESSCODE,当前产品ID下的未关联商品列表
                 */
                BaseProduct lmmProduct = new BaseProduct();
                lmmProduct.setCompanyCode(COMPANY_LMM.toUpperCase()+COMPANY_CODE_SUFFIX);
                lmmProduct.setBusinessCode(baseProduct.getBusinessCode());//业务编号
                lmmProduct.setProdId(baseProduct.getProdId());//产品id

                List<BaseCommodity> lmmCommodities = baseCommodityService.selectCommodityByBaseProduct(lmmProduct);
                /**
                 * 驴妈妈当前BUSINESSCODE,当前产品ID下不存在商品
                 */
                if(lmmCommodities==null||lmmCommodities.isEmpty())
                {
                    continue;
                }

                /**
                 * 查询当前prodid及businessCode,对应的未关联驴妈妈商品
                 */
                for(BaseCommodity lmm:lmmCommodities)
                {
                    /**
                     * 过滤掉组合商品
                     */
                    if(baseCommodityService.isCombinedBaseCommodity(lmm))
                    {
                        COMBINEDCOMMODITIES +=1;
                        continue;
                    }

                    /**
                     * 需要被匹配的驴妈妈商品个数
                     */
                    NEEDMATCH +=1;

                    /**
                     * 此处为单个驴妈妈商品对一个链表的其他商品的匹配
                     */
                    for(String company : companyList)
                    {
                        baseProduct.setCompanyCode(company.toUpperCase()+COMPANY_CODE_SUFFIX);//某公司
                        /**
                         * 与驴妈妈商品为相同的城市，不同城市的商品默认不具有可对比性
                         */
                        baseProduct.setCityCode(lmm.getCityCode());
                        /**
                         * 获得某个公司,当前城市下未关联的商品
                         */
                        List<BaseCommodity> baseCommodities= baseCommodityService.selectCommodityByBaseProduct(baseProduct);
                        BaseCommodity bestMatched = baseCommodityService.getBestMatched(lmm,baseCommodities);
                        /**
                         * 当获得了最佳匹配后，进行数据库操作将最佳匹配的数据插入数据库
                         */
                        if(bestMatched!=null)
                        {
                            /**
                             * 组装要插入的数据库数据
                             */
                            CommodityRel commodityRel = this.assembleCommodity(bestMatched,lmm);

                            /**
                             * 插入数据库
                             */
                            this.insertCommodityRel(commodityRel);
                        }
                    }
                }
            }
        }catch (Exception e)
        {
            logger.info(" *** 通用商品自动匹配异常结束 *** "+e.getMessage());
        }finally {
            afterMatch();
            logger.info(" *** 通用商品自动匹配结束 *** ");
        }
    }

    /**
     * 匹配前记录数据
     */
    public void beforeMatch()
    {
        /**
         * 获取业务类型
         */
        List<String> businessList =  relevanceCommodityService.selectBusinessCodes();
        if(businessList==null||businessList.isEmpty())
        {
            return;
        }
        /**
         * 查找每个公司对应的业务类型，初始时的条数
         */
        List<String> companyList = relevanceCommodityService.selectCompanyCodes();
        if(companyList==null||companyList.isEmpty())
        {
            return;
        }

        for(String business :businessList)
        {
            /**
             * 按照业务、公司初始化匹配前数据
             */
            for(String company : companyList)
            {
                CommodityRel commodityRel = new CommodityRel();
                commodityRel.setBusiness_code(business);
                commodityRel.setCompany_code(company);
                int ret = relevanceCommodityService.selectCounts(commodityRel);
                counts.put(business+UNDERLINE+company,ret);
            }

        }
    }

    /**
     * 返回公司名字
     * @param code
     * @return
     */
    public String getCompanyName(String code)
    {
        String ret = NONE;
        EnumSet<Company> companies = EnumSet.allOf(Company.class);
        for(Company c : companies)
        {
            if(code.toUpperCase().equals(c.getCode()))
            {
                ret = c.getName();
                break;
            }
        }
        return ret;
    }

    /**
     * 返回业务名称
     * @param value
     * @return
     */
    public String getBusinessName(String value)
    {
        String ret = NONE;
        EnumSet<BusinessCode> businesses = EnumSet.allOf(BusinessCode.class);
        for(BusinessCode b :businesses)
        {
            if(value.toUpperCase().equals(b.getValue()))
            {
                ret = b.getDesc();
                break;
            }
        }
        return ret;
    }

    /**
     * 匹配后做好日志输出
     */
    public void afterMatch()
    {
        /**
         * 获取业务类型
         */
        List<String> businessList =  relevanceCommodityService.selectBusinessCodes();
        if(businessList==null||businessList.isEmpty())
        {
            return;
        }
        /**
         * 查找每个公司对应的业务
         */
        List<String> companyList = relevanceCommodityService.selectCompanyCodes();
        if(companyList==null||companyList.isEmpty())
        {
            return;
        }
        logger.info(" *** 本次需要被匹配的驴妈妈商品数为 "+NEEDMATCH+" 个！");
        logger.info(" *** 本次忽略匹配的驴妈妈组合商品数为 "+COMBINEDCOMMODITIES+" 个！");
        for(String business :businessList)
        {
            /**
             * 业务类型的中文描述
             */
            String _business = getBusinessName(business);

            /**
             * 业务公司的名称
             */
            String _company = NONE;
            /**
             * 当前业务已经匹配共计多少条
             */
            int businessTotal = 0;
            for(String company : companyList)
            {
                _company = getCompanyName(company);
                CommodityRel commodityRel = new CommodityRel();
                commodityRel.setBusiness_code(business);
                commodityRel.setCompany_code(company);
                int ret = relevanceCommodityService.selectCounts(commodityRel);
                /**
                 * 存在新加入的公司的商品，此时在成员变量中获取到的该值为null
                 */
                Integer before = counts.get(NONE+business+UNDERLINE+company);
                int _before = 0;
                if(before!=null)
                {
                    _before = before;
                }
                businessTotal += (ret - _before);
                logger.info(" *** 本次匹配 * "+_business+" * "+_company+" "+(ret - _before)+ " 条！");
            }
            logger.info(" *** 本次匹配 * "+_business+" * 共计 "+businessTotal+ " 条！");
        }
    }

    /**
     * 新增数据库表commodity_rel数据
     */
    public void insertCommodityRel(CommodityRel commodityRel)
    {
        commodityService.insertCommodityRel(commodityRel);
    }

    /**
     * 组装需要入库的数据类型
     * @param other
     */
    public CommodityRel assembleCommodity(BaseCommodity other,BaseCommodity lmm)
    {
        CommodityRel commodityRel = new CommodityRel();
        commodityRel.setProd_id(lmm.getProductId());//设置驴妈妈产品id
        commodityRel.setCommodity_id(lmm.getCommodityId());//设置驴妈妈商品id
        if(!isNone(other.getCompanyCode()))
        {
            //由于该数据库表一直存储的习惯为：mt,xc,tn,tc
            String company = other.getCompanyCode().split(UNDERLINE)[0].toLowerCase();
            commodityRel.setCompany_code(company);//设置公司
        }
        commodityRel.setBusiness_code(other.getBusinessCode());//设置业务编码
        commodityRel.setRel_commodity_id(other.getCommodityId());//设置商品id
        commodityRel.setRel_commodity_name(other.getCommodityName());//设置商品名称
        commodityRel.setRel_prod_id(other.getProductId());//设置产品id
        return commodityRel;
    }

    /**
     * 非空判断
     * @param str
     * @return
     */
    public boolean isNone(String str)
    {
        boolean ret = false;
        if(str==null || StringUtils.isEmpty(str))
        {
            ret = true;
        }
        return ret;
    }

    /**
     * 返回需要匹配的compamy
     * @param base
     * @return
     */
    public List<String> needMatchCompany(BaseProduct base)
    {
        List<String> list = new ArrayList<>();
        Map<String,String> map = ReflectTools.getFieldsAndValues(base);
        for(String key:map.keySet())
        {
            if(key==null)
            {
                continue;
            }
            /**
             * 业务为EL,并且EL对应的产品id不为空
             */
            if(COMPANY_EL.equals(key.replaceAll(BEREPLACED_ID,NONE).toLowerCase())
                    &&!isNone(map.get(key)))
            {
                list.add(COMPANY_EL);
                continue;
            }
            if(COMPANY_MT.equals(key.replaceAll(BEREPLACED_ID,NONE).toLowerCase())
                    &&!isNone(map.get(key)))
            {
                list.add(COMPANY_MT);
                continue;
            }
            if(COMPANY_XC.equals(key.replaceAll(BEREPLACED_ID,NONE).toLowerCase())
                    &&!isNone(map.get(key)))
            {
                list.add(COMPANY_XC);
                continue;
            }
            if(COMPANY_TN.equals(key.replaceAll(BEREPLACED_ID,NONE).toLowerCase())
                    &&!isNone(map.get(key)))
            {
                list.add(COMPANY_TN);
                continue;
            }
            if(COMPANY_QNR.equals(key.replaceAll(BEREPLACED_ID,NONE).toLowerCase())
                    &&!isNone(map.get(key)))
            {
                list.add(COMPANY_QNR);
                continue;
            }
            if(COMPANY_TC.equals(key.replaceAll(BEREPLACED_ID,NONE).toLowerCase())
                    &&!isNone(map.get(key)))
            {
                list.add(COMPANY_TC);
                continue;
            }
        }
        return list;
    }

    /**
     * 初始化加载容器
     */
    private void init()
    {
        relevanceProductService = (RelevanceProductService) SpringContextUtil.getBean(RelevanceProductService.class);
        baseCommodityService = (BaseCommodityService)SpringContextUtil.getBean(BaseCommodityService.class);
        commodityService =(RelevanceCommodityService)SpringContextUtil.getBean(RelevanceCommodityService.class);
        relevanceCommodityService=(RelevanceCommodityService)SpringContextUtil.getBean(RelevanceCommodityService.class);
    }

    @Override
    public void runJob(JobExecutionContext context, String parameter) {
        init();
        matchCommodities();
    }
}
